﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using LuaInterface;
using System.Collections;
using Microsoft.Xna.Framework.Graphics;

namespace catch_me_ai {
    public class Mapa {
        private const int TAM_MAX_MAPA_LINHA = 100;
        private const int TAM_MAX_MAPA_COLUNA = 100;

        private Lua lua;
        private int[,] elementos = new int[TAM_MAX_MAPA_LINHA, TAM_MAX_MAPA_COLUNA]; // elementos que estão no mapa. Ex: paredes, portões...
        private Vector2 tamanhoTile = new Vector2(15, 15);
        private Vector2 posicaoInicialJogador;
        private Vector2 posicaoInicialNPC;
        private List<String> ordemFases;
        private String faseAtual;
        private int proximaFase = 0;
        private bool isUltimaFase = false;

        public Mapa(String arquivoMapaLua) {
            lua = new Lua();
            lua.DoFile(arquivoMapaLua);
            ordemFases = new List<String>();
            carregarMapa();
        }

        public void carregarMapa() {
            if (this.faseAtual == null) {
                validaOrdemFases();
                validaExistenciaMapas();
                validaTamanhoMapa();
                selecionaMapa();
                carregarElementos();
            } else {
                selecionaMapa();
                validaTamanhoMapa();
                carregarElementos();
            }
        }

        private void validaOrdemFases() {
            try {
                foreach (DictionaryEntry member in lua.GetTable("_ordemFases")) {
                    ordemFases.Add(member.Value.ToString());
                }
            }catch(Exception){
                throw new InvalidMapaException("Nao foi encontrado no arquivo de configuracoes a entrada: _ordemFases");
            }
        }

        private void selecionaMapa() {
            this.faseAtual = ordemFases[proximaFase];
            if(proximaFase >= (ordemFases.Count - 1)){
                isUltimaFase = true;
            }else{
                proximaFase++;
            }
        }

        private void carregarElementos() {
            int linha = 0;
            int totalLinhas = lua.GetTable(this.faseAtual).Values.Count - 1;

            foreach (DictionaryEntry member in lua.GetTable(this.faseAtual)) {
                Array conteudoLinhas = member.Value.ToString().ToCharArray();
                int colunaQtde = 0;

                foreach (char conteudo in conteudoLinhas) {
                    int valorConteudo = int.Parse(conteudo.ToString());

                    // checa primeira ou última linha
                    if (linha == 0 || linha == totalLinhas) { 
                        // todas as colunas devem ser 1 (parede) ou 4 (portão) 
                        if (valorConteudo != 1 && valorConteudo != 4) {
                            valorConteudo = 1;
                        }


                    } else { // checa demais linhas
                        //coluna 0 deve ser 1 ou 4
                        //ultima coluna deve ser 1 ou 4
                        if (colunaQtde == 0 || colunaQtde == (conteudoLinhas.Length - 1)) {
                            if (valorConteudo != 1 && valorConteudo != 4) {
                                valorConteudo = 1;
                            }
                        } else { // qualquer 'parede' interna é removida.
                            if (valorConteudo != 0 && valorConteudo != 2 && 
                                valorConteudo != 3 && valorConteudo != 5) {
                                valorConteudo = 0;
                            }
                        }
                    }

                    elementos[linha, colunaQtde] = valorConteudo;
                    colunaQtde++;
                }
                linha++;
            }
        }

        // Valida se os mapas informados na ordem existem
        private void validaExistenciaMapas() {
            foreach (String fase in ordemFases) {
                try {
                    foreach (DictionaryEntry member in lua.GetTable(fase)) {}
                }catch(Exception){
                    throw new InvalidMapaException("O mapa/fase \"" + fase + "\" nao foi encontrado no arquivo de configuracoes.");
                }
            }
        }

        // Valida se o tamanho do mapa está dentro do permitido.
        private void validaTamanhoMapa() {
            foreach (String fase in ordemFases) {
                int totalLinhas = lua.GetTable(fase).Values.Count;
                foreach (DictionaryEntry member in lua.GetTable(fase)) {
                    int totalColunas = member.Value.ToString().ToCharArray().Length;
                    //ERRO, não deve deixar carregar
                    if (totalLinhas > TAM_MAX_MAPA_LINHA || totalColunas > TAM_MAX_MAPA_COLUNA) {
                        throw new InvalidMapaException("o limite maximo permitido de 100 linhas X 100 colunas por mapa foi excedido para o mapa \"" + fase + "\".");
                    }
                    break;
                }
            }
        }

        // Valida se existe uma configuração para a fase/mapa atual,
        // se existir carrega essas configurações, caso contrário
        // assumir os valores default.
        public ValorItemMapa carregarConfiguracoesMapa() {
            ValorItemMapa valorItemMapa = new ValorItemMapa();
            try {
                foreach (DictionaryEntry member in lua.GetTable("_" + this.faseAtual)) {
                    String key = member.Key.ToString();
                    int valor = Convert.ToInt32(member.Value);
                    valorItemMapa.add(key, valor);
                }
            } catch (Exception) {
                return valorItemMapa;
            }

            return valorItemMapa;
        }

        // Carrega os itens (paredes, portões, diamantes, etc...) contidos no mapa.
        public List<Item> carregarItensMapa() {
            List<Item> listaItens = new List<Item>();
            Vector2 posicao;
            for (int linha = 0; linha < elementos.GetLength(0); linha++) {
                for (int coluna = 0; coluna < elementos.GetLength(1); coluna++) {

                    // Carrega paredes
                    if (elementos[linha, coluna] == 1) {
                        posicao = new Vector2(coluna * tamanhoTile.X, linha * tamanhoTile.X);
                        listaItens.Add(new Item(posicao, TipoItem.Parede, false));
                    }

                    // Carrega jogador
                    if (elementos[linha, coluna] == 2) {
                        posicao = new Vector2(coluna * tamanhoTile.X, linha * tamanhoTile.X);
                        posicaoInicialJogador = posicao;
                    }

                    // Carrega o NPC
                    if (elementos[linha, coluna] == 3) {
                        posicao = new Vector2(coluna * tamanhoTile.X, linha * tamanhoTile.X);
                        posicaoInicialNPC = posicao;
                    }

                    // Carrega portões
                    if (elementos[linha, coluna] == 4) {
                        posicao = new Vector2(coluna * tamanhoTile.X, linha * tamanhoTile.X);
                        listaItens.Add(new Item(posicao, TipoItem.Portao, false));
                    }

                    // Carrega Diamante (itens)
                    if (elementos[linha, coluna] == 5) {
                        posicao = new Vector2(coluna * tamanhoTile.X, linha * tamanhoTile.X);
                        listaItens.Add(new Item(posicao, TipoItem.Diamante, true));
                    }
                }
            }

            return listaItens;
        }

        public Vector2 getPosicaoInicialJogador() {
            return posicaoInicialJogador;
        }

        public Vector2 getPosicaoInicialNPC() {
            return posicaoInicialNPC;
        }

        public bool getIsUltimaFase() {
            return isUltimaFase;
        }

    }
}
